package com.bestcem.xm.deliver.controller.v2;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bestcem.xm.common.core.annotation.XmGet;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.component.mybatis.base.ResultPage;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.deliver.controller.param.WechatmpRecordsPageParam;
import com.bestcem.xm.deliver.controller.v2.param.CreateWechatMpdeliversParam;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverWechatmpRecordVo;
import com.bestcem.xm.deliver.convert.DeliverConvertMapper;
import com.bestcem.xm.deliver.entity.DeliverDeliver;
import com.bestcem.xm.deliver.entity.DeliverDeliverSurveyData;
import com.bestcem.xm.deliver.entity.DeliverWechatmpDeliver;
import com.bestcem.xm.deliver.entity.DeliverWechatmpRecord;
import com.bestcem.xm.deliver.enums.*;
import com.bestcem.xm.deliver.grpc.client.OpenPlatformGrpcClient;
import com.bestcem.xm.deliver.grpc.client.PushGrpcClient;
import com.bestcem.xm.deliver.grpc.client.SurveyGrpcClient;
import com.bestcem.xm.deliver.grpc.client.dto.SurveyRespondentDto;
import com.bestcem.xm.deliver.grpc.client.dto.WechatOfficialInfoDto;
import com.bestcem.xm.deliver.service.DeliverWechatmpDeliverService;
import com.bestcem.xm.deliver.service.DeliverWechatmpRecordService;
import com.bestcem.xm.deliver.util.PageUtil;
import com.bestcem.xm.openplatform.grpc.v1.services.ExtParam;
import com.bestcem.xm.openplatform.grpc.v1.services.ExtParamStatus;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.deliver.util.DeliverConstant.WECHATMP_SEND_STATUS_DICT;


@Slf4j
@Api(tags = "微信投放")
@RestController
@RequiredArgsConstructor
@RequestMapping("/deliver/v2")
public class DeliverWechatmpController {

    private @NonNull SurveyGrpcClient surveyGrpcClient;
    private @NonNull PushGrpcClient pushGrpcClient;
    private @NonNull OpenPlatformGrpcClient openPlatformGrpcClient;

    private @NonNull DeliverWechatmpDeliverService wechatMpdeliverService;

    private @NonNull DeliverWechatmpRecordService wechatMprecordService;

    private @NonNull com.bestcem.xm.deliver.service.DeliverDeliverService deliverService;

    private @NonNull com.bestcem.xm.deliver.service.DeliverDeliverSurveyDataService dliverSurveyDataService;

    private @NonNull DeliverConvertMapper deliverConvertMapper;

    @ApiOperation(value = "获取当前租户所有授权的公众号")
    @GetMapping("/wechatmp")
    public List<WechatOfficialInfoDto> getWechatmp() {
        return wechatMpdeliverService.getWechatmp();
    }

    @ApiOperation(value = "公众号消息模板")
    @GetMapping("/wechatmptemplates/")
    public JSONObject getWechatTemplates(@RequestParam("app_id") String appId) {
        return wechatMpdeliverService.getWechatTemplates(appId);
    }

    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataTypeClass = Long.class, name = "page", value = "页码"),
            @ApiImplicitParam(paramType = "query", dataTypeClass = Long.class, name = "rowsPerPage", value = "每页条数")
    })
    @ApiOperation(value = "公众号投放详情分页查询")
    @GetMapping("/wechatmprecords/")
    public ResultPage<DeliverWechatmpRecordVo> pageWechatmpRecords(@ApiIgnore Page<DeliverWechatmpRecord> page, @XmGet WechatmpRecordsPageParam param) {
        String mp_deliver_id = Optional.ofNullable(param.getWechatDeliverId())
                .orElseThrow(() -> new BusinessException("缺少投放id"));

        String project_id = Optional.ofNullable(param.getProjectId())
                .orElseThrow(() -> new BusinessException("survey_id required"));

        DeliverWechatmpDeliver mp_deliver = Optional.ofNullable(wechatMpdeliverService.getById(mp_deliver_id))
                .orElseThrow(() -> new BusinessException(String.format("WeChatMPDeliver[id=%s] not found", mp_deliver_id)));

        String deliver_id = mp_deliver.getDeliverId();
        String status = param.getStatus();
        Integer check_submit = mp_deliver.getCheckSubmit();
        String survey_resp_status_arg = param.getSurveyRespStatus();
        String search = param.getSearch();
        if (mp_deliver.getMpTtype().equals(WechatMpdeliverMpTypeEnum.WECHATMPDELIVER_MP_TTYPE_CONDITION.getValue())) {
            LambdaQueryWrapper<DeliverWechatmpRecord> queryWrapper = new LambdaQueryWrapper<>();
            commonWrapper(queryWrapper, status, mp_deliver_id, search);
            queryWrapper.eq(StrUtil.isNotBlank(survey_resp_status_arg), DeliverWechatmpRecord::getRspdStatus, survey_resp_status_arg);

            //默认按创建时间降序排序
            queryWrapper.orderByDesc(DeliverWechatmpRecord::getCreatedDt);
            page = wechatMprecordService.page(page, queryWrapper);
            List<DeliverWechatmpRecordVo> rets = page.getRecords().stream()
                    .map(obj -> {
                        DeliverWechatmpRecordVo item = deliverConvertMapper.wechatRecord2Vo(obj);
                        item.setSurveyRespStatus(item.getRspdStatus());
                        if (check_submit.equals(0)) {
                            JSONObject query_params = new JSONObject();
                            query_params.put("project_id", project_id);
                            query_params.put("deliver_id", deliver_id);
                            query_params.put("status", RespondentStatusEnum.RESPONDENT_STATUS_FINISH.getValue());
                            query_params.put("dlvr_rid", item.getId());
                            List<SurveyRespondentDto> resps = surveyGrpcClient.listRespondent(query_params);
                            item.setFinished(resps.size());
                        }
                        return item;
                    }).collect(Collectors.toList());
            return PageUtil.getResultPage(page.getCurrent(), page.getTotal(), rets);
        } else {
            LambdaQueryWrapper<DeliverDeliverSurveyData> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(DeliverDeliverSurveyData::getMemberId, DeliverDeliverSurveyData::getUrgeNums, DeliverDeliverSurveyData::getSurveyNums, DeliverDeliverSurveyData::getSurveyStatus);
            queryWrapper.eq(StrUtil.isNotBlank(param.getSurveyStatus()), DeliverDeliverSurveyData::getSurveyStatus, param.getSurveyStatus());
            queryWrapper.eq(StrUtil.isNotBlank(deliver_id), DeliverDeliverSurveyData::getDeliverId, deliver_id);
            List<DeliverDeliverSurveyData> list = dliverSurveyDataService.list(queryWrapper);

            Map<String, List<Integer>> member_map = list
                    .stream()
                    .collect(Collectors.toMap(DeliverDeliverSurveyData::getMemberId, v -> Arrays.asList(v.getUrgeNums(), v.getSurveyNums(), v.getSurveyStatus()), (a, b) -> a));
            Set<String> member_surveydata_ids = member_map.keySet();

            List<String> member_ids = deliverService.getDeliverMemberIdList(deliver_id, DeliverTtypeEnum.DELIVER_TTYPE_WECHATMP);
            Map<String, Integer> member_resp_maps = new HashMap<>();
            deliverService.getMemberRespMaps(project_id, survey_resp_status_arg, deliver_id, check_submit, member_resp_maps, member_ids);
            log.info("投放member_resp_maps---{}", JSON.toJSONString(member_resp_maps));
            Set<String> member_resp_ids = member_resp_maps.keySet();

            LambdaQueryWrapper<DeliverWechatmpRecord> pagequeryWrapper = new LambdaQueryWrapper<>();
            // 这里效果就是求不重复的member_id，python用group by，但是mybatis-plus计算count有语法错误,示例如下
            //SELECT COUNT(*) FROM (SELECT member_id FROM ds_deliver_wechatmprecord WHERE (mp_deliver_id = '625810eaaace700009cfe140') GROUP BY member_id ORDER BY created_dt DESC) TOTAL
            //对照数据库发现mp_ttype=0时候， member_id, mp_deliver_id 组合起来唯一
            pagequeryWrapper.select(DeliverWechatmpRecord::getMemberId);
            commonWrapper(pagequeryWrapper, status, mp_deliver_id, search);
            //默认按创建时间降序排序
            pagequeryWrapper.orderByDesc(DeliverWechatmpRecord::getCreatedDt);
            if (StrUtil.isNotBlank(survey_resp_status_arg)) {
                HashSet<String> set2 = new HashSet<>(member_resp_ids);
                member_ids = new ArrayList<>(CollectionUtils.intersection(member_surveydata_ids, set2));
                pagequeryWrapper.in(!CollectionUtils.isEmpty(member_ids), DeliverWechatmpRecord::getMemberId, member_ids);
            }

            page = wechatMprecordService.page(page, pagequeryWrapper);
            List<DeliverWechatmpRecord> items = page.getRecords();
            log.info("items---{}", JSON.toJSONString(page.getRecords()));
            List<Map<String, Object>> wechatmp_record_data = new ArrayList<>();
            for (DeliverWechatmpRecord item : items) {
                LambdaQueryWrapper<DeliverWechatmpRecord> wrapper = new LambdaQueryWrapper<>();
                commonWrapper(wrapper, status, mp_deliver_id, search);
                wrapper.orderByDesc(DeliverWechatmpRecord::getId);
                wrapper.eq(StrUtil.isNotEmpty(item.getMemberId()), DeliverWechatmpRecord::getMemberId, item.getMemberId());
                //如果是多个，逻辑就对不上了
                DeliverWechatmpRecord data = wechatMprecordService.getOne(wrapper, true);
                Map<String, Object> mp = new HashMap<>();
                //mp.put("id", "member_id");
                mp.put("ret", data);
                wechatmp_record_data.add(mp);
            }
            List<DeliverWechatmpRecordVo> rets = wechatmp_record_data.stream()
                    .map(imt -> setItem(imt, check_submit, member_map, member_resp_maps)).collect(Collectors.toList());
            return PageUtil.getResultPage(page.getCurrent(), page.getTotal(), rets);
        }
    }

    /**
     * {"survey_id":"62846a423e2c0c000a1b2661","_deliver_name":"公众号投放(5)","deliver_g_id":"","survey_submit_type":0,"is_sms_added":false,"check_submit":1,"is_check":0,"is_delay":0,"deliver_time":null,"anti_distur_times":["00:00-08:00"],"mp_ttype":0}
     * {"code": 0, "data": {"id": "6375da533e2c0c000a7f025b"}}
     *
     * @return com.alibaba.fastjson.JSONObject
     * @author chenglong.yue <chenglong.yue@idiaoyan.com>
     * @date 2022/11/17 14:56
     */
    @ApiOperation(value = "新建公众号投放-保存")
    @PostMapping("/wechatmpdelivers/")
    public JSONObject createWechatMpdelivers(@RequestBody @Validated CreateWechatMpdeliversParam param) {
        return wechatMpdeliverService.createWechatMpdelivers(param);
    }

    @ApiOperation(value = "新建公众号投放-更新")
    @PutMapping("/wechatmpdeliver/{id:[a-fA-F0-9]{24}}")
    public JSONObject updateWechatmpdelivers(@PathVariable String id, @RequestBody JSONObject param) {
        DeliverWechatmpDeliver wechatmpdeliver = Optional.ofNullable(wechatMpdeliverService.getById(id))
                .orElseThrow(() -> new BusinessException(String.format("WeChatMPDeliver[id=%s] not found", id)));

        DeliverDeliver deliver = Optional.ofNullable(deliverService.getById(wechatmpdeliver.getDeliverId()))
                .orElseThrow(() -> new BusinessException(String.format("DeliverDeliver[id=%s] not found", wechatmpdeliver.getDeliverId())));

        String appid = param.getOrDefault("appid", "").toString();
        if (StrUtil.isBlank(appid)) {
            throw new BusinessException("发送的公众号appid不能为空");
        }

        String mp_name = param.getOrDefault("mp_name", "").toString();
        if (StrUtil.isBlank(mp_name)) {
            throw new BusinessException("发送的公众号名称不能为空");
        }

        List<WechatOfficialInfoDto> mp_info_list = pushGrpcClient.listAccountInfo(SecurityContextHolder.getOrgId());
        boolean a = mp_info_list.stream().noneMatch(it -> Objects.equals(it.getAppId(), appid));
        if (a) {
            throw new BusinessException("需要授权的公众号appid");
        }

        boolean b = mp_info_list.stream().noneMatch(it -> Objects.equals(it.getNickname(), mp_name));
        if (b) {
            throw new BusinessException("需要授权的公众号名称");
        }

        Optional.of(param.getJSONObject("mp_template_content"))
                .map(mp_template_content -> mp_template_content.getJSONArray("content"))
                .ifPresent(contentList -> {
                    for (int i = 0; i < contentList.size(); i++) {
                        JSONObject content = contentList.getJSONObject(i);
                        String value = content.getString("value");
                        if (StrUtil.length(value) > 30) {
                            throw new BusinessException("赋值输入框最多30字符");
                        }
                    }
                });

        Optional.of(param.getJSONObject("mp_template_content"))
                .map(mp_template_content -> mp_template_content.getJSONObject("first"))
                .ifPresent(first -> {
                    String value = first.getString("value");
                    if (StrUtil.length(value) > 30) {
                        throw new BusinessException("first输入框最多30字符");
                    }
                });

        Optional.of(param.getJSONObject("mp_template_content"))
                .map(mp_template_content -> mp_template_content.getJSONObject("remark"))
                .ifPresent(remark -> {
                    String value = remark.getString("value");
                    if (StrUtil.length(value) > 30) {
                        throw new BusinessException("remark输入框最多30字符");
                    }
                });

        JSONArray ext_params = param.getJSONArray("ext_params");
        for (int i = 0; i < ext_params.size(); i++) {
            JSONObject ext_param = ext_params.getJSONObject(i);
            ExtParam extparam = openPlatformGrpcClient.getExtParam(ext_param.getString("extparam_id"));
            if (extparam.getStatusValue() == ExtParamStatus.EXTPARAM_STATUS_DELETE_VALUE) {
                throw new BusinessException(String.format("资源不存在, 外部参数[extparam_id=%s]", ext_param.getString("extparam_id")));
            }
            if (!extparam.getName().equals(ext_param.getString("extparam_name"))) {
                throw new BusinessException(String.format("资源不存在, 外部参数[extparam_name=%s]", ext_param.getString("extparam_name")));
            }
            if (extparam.getDtypeValue() != ext_param.getIntValue("extparam_type")) {
                throw new BusinessException(String.format("资源不存在, 外部参数[extparam_type=%s]", ext_param.getString("extparam_type")));
            }
        }
        return wechatMpdeliverService.updateWechatmpdelivers(id, param, wechatmpdeliver, deliver);
    }

    @ApiOperation(value = "公众号投放-编辑")
    @PutMapping("/wechatmpdeliver/edit/{id:[a-fA-F0-9]{24}}")
    public JSONObject editWechatmpdelivers(@PathVariable String id, @RequestBody JSONObject param) {
        DeliverWechatmpDeliver wechatmpdeliver = Optional.ofNullable(wechatMpdeliverService.getById(id))
                .orElseThrow(() -> new BusinessException(String.format("WeChatMPDeliver[id=%s] not found", id)));

        DeliverDeliver deliver = Optional.ofNullable(deliverService.getById(wechatmpdeliver.getDeliverId()))
                .orElseThrow(() -> new BusinessException(String.format("DeliverDeliver[id=%s] not found", wechatmpdeliver.getDeliverId())));

        if (wechatmpdeliver.getIsCheck().equals(1)) {
            if (DeliverStatusEnum.getCheck1Value().contains(deliver.getStatus())) {
                throw new BusinessException("投放状态不支持编辑1");
            }
        } else {
            if (DeliverStatusEnum.getCheck0Value().contains(deliver.getStatus())) {
                throw new BusinessException("投放状态不支持编辑2");
            }
        }

        return wechatMpdeliverService.editWechatmpdelivers(id, param, wechatmpdeliver, deliver);
    }

    @ApiOperation(value = "公众号投放-导出")
    @PostMapping("/wechatmpdeliver/export/")
    public void export(@RequestBody JSONObject param, HttpServletResponse response) {
        log.info("/wechatmpdeliver/export/传递参数param:{}", param.toJSONString());
        Optional.ofNullable(param.getString("project_id"))
                .orElseThrow(() -> new BusinessException("project_id required"));

        DeliverWechatmpDeliver mp_deliver = Optional.ofNullable(wechatMpdeliverService.getById(param.getString("wechatmp_deliver_id")))
                .orElseThrow(() -> new BusinessException(String.format("WeChatMPDeliver[id=%s] not found", param.getString("wechatmp_deliver_id"))));

        DeliverDeliver deliver = Optional.ofNullable(deliverService.getById(mp_deliver.getDeliverId()))
                .orElseThrow(() -> new BusinessException(String.format("DeliverDeliver[id=%s] not found", mp_deliver.getDeliverId())));

        wechatMpdeliverService.export(param, response, mp_deliver, deliver);
    }

    private DeliverWechatmpRecordVo setItem(Map<String, Object> item, Integer check_submit, Map<String, List<Integer>> member_map, Map<String, Integer> member_resp_maps) {
        DeliverWechatmpRecord old = JSONObject.parseObject(JSON.toJSONString(item.get("ret")), DeliverWechatmpRecord.class);
        DeliverWechatmpRecordVo vo = deliverConvertMapper.wechatRecord2Vo(old);
        String member_id = old.getMemberId();
        int urge_n, survey_n, survey_s;
        if (member_map.containsKey(member_id)) {
            List<Integer> list = member_map.get(member_id);
            urge_n = list.stream().findFirst().orElse(0);
            survey_n = list.get(1);
            survey_s = list.get(2);
        } else {
            urge_n = 0;
            survey_n = 0;
            survey_s = DeliverSurveyDataSurveyStatusEnum.DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue();
        }

        if (check_submit.equals(0)) {
            vo.setFinished(member_resp_maps.getOrDefault(member_id, 0));
        } else {
            vo.setSurveyRespStatus(member_resp_maps.getOrDefault(member_id, RespondentStatusEnum.RESPONDENT_STATUS_NOTSTART.getValue()));
        }

        if (StrUtil.isNotEmpty(old.getMsgid()) && old.getStatus().equals(WechatMprecordStatusEnum.WECHATMPRECORD_STATUS_SENDING.getValue())) {
            Integer statusCode = pushGrpcClient.getTemplateMsgStatus(old.getMsgid());
            Integer newstatus = WECHATMP_SEND_STATUS_DICT.get(statusCode);
            vo.setStatus(newstatus);

            // 查询还要update吗，好骚
            LambdaUpdateWrapper<DeliverWechatmpRecord> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(DeliverWechatmpRecord::getId, old.getId());
            DeliverWechatmpRecord update = new DeliverWechatmpRecord();
            update.setStatus(newstatus);
            wechatMprecordService.update(update, updateWrapper);
        }
        vo.setUrgeNums(urge_n);
        vo.setSurveyNums(survey_n);
        vo.setSurveyRespStatus(survey_s);
        return vo;
    }

    private void commonWrapper(LambdaQueryWrapper<DeliverWechatmpRecord> wrapper, String status, String mp_deliver_id, String search) {
        wrapper.eq(StrUtil.isNotBlank(mp_deliver_id), DeliverWechatmpRecord::getMpDeliverId, mp_deliver_id);
        wrapper.eq(StrUtil.isNotBlank(status), DeliverWechatmpRecord::getStatus, status);
        wrapper.and(StrUtil.isNotBlank(search), wrap ->
                wrap.like(DeliverWechatmpRecord::getUsername, search)
                        .or()
                        .like(DeliverWechatmpRecord::getNickname, search)
                        .or()
                        .like(DeliverWechatmpRecord::getOpenid, search)
        );
    }
}
